﻿using System.IO;
using System.Text;

namespace Import_glTF.gltf
{
    public enum ChunkType : uint
    {
        JSON = 0x4E4F534A,
        BIN = 0x004E4942
    }
    public class GlbChunk
    {
        public uint Length { get; set; }
        public ChunkType Type { get; protected set; }
        public byte[] Data { get; set; }
    }
    public class JsonChunk : GlbChunk
    {
        public JsonChunk()
        {
            Type = ChunkType.JSON;
        }
        public static JsonChunk FromString(string json)
        {
            byte[] datas = Encoding.UTF8.GetBytes(json);
            return new JsonChunk { Length = (uint)datas.Length, Data = datas };
        }
        public override string ToString()
        {
            return Encoding.UTF8.GetString(Data);
        }
    }
    public class BinChunk : GlbChunk
    {
        public BinChunk()
        {
            Type = ChunkType.BIN;
        }
    }
    public class GlbFile
    {
        public const uint Magic = 0x46546C67;
        public const uint Version = 2;
        public uint Size { get; set; }
        public JsonChunk Json { get; set; }
        public BinChunk Bin { get; set; }
        public static GlbFile ReadFromFile(string fileName)
        {
            GlbFile glbFile = new GlbFile();
            using (FileStream fileStream = File.OpenRead(fileName))
            {
                BinaryReader reader = new BinaryReader(fileStream);
                reader.ReadBytes(2 * sizeof(uint));//跳过两个uint，八个字节
                glbFile.Size = reader.ReadUInt32();
                JsonChunk jsonChunk = new JsonChunk
                {
                    Length = reader.ReadUInt32()
                };
                reader.ReadUInt32();//跳过类型
                jsonChunk.Data = reader.ReadBytes((int)jsonChunk.Length);
                glbFile.Json = jsonChunk;
                BinChunk binChunk = new BinChunk
                {
                    Length = reader.ReadUInt32()
                };
                reader.ReadUInt32();//跳过类型
                binChunk.Data = reader.ReadBytes((int)binChunk.Length);
                glbFile.Bin = binChunk;
                reader.Close();
                fileStream.Close();
            }
            return glbFile;
        }
        public void WriteToFile(string fileName)
        {
            using (FileStream fileStream = File.OpenWrite(fileName))
            {
                BinaryWriter writer = new BinaryWriter(fileStream);
                writer.Write(GlbFile.Magic);
                writer.Write(GlbFile.Version);
                writer.Write(this.Size);
                writer.Write(this.Json.Length);
                writer.Write((uint)ChunkType.JSON);
                writer.Write(this.Json.Data);
                writer.Write(this.Bin.Length);
                writer.Write((uint)ChunkType.BIN);
                writer.Write(this.Bin.Data);
                writer.Close();
                fileStream.Close();
            }
        }
        public void ReplaceJsonChunk(JsonChunk chunk)
        {
            int deltaSize = (int)chunk.Length - (int)Json.Length;
            Json = chunk;
            Size = (uint)(Size + deltaSize);
        }
        public void ReplaceJsonChunk(string jsonContent)
        {
            JsonChunk jsonChunk = JsonChunk.FromString(jsonContent);
            int deltaSize = (int)jsonChunk.Length - (int)Json.Length;
            Json = jsonChunk;
            Size = (uint)(Size + deltaSize);
        }
    }
}
